package Modelo;

import Controlador.Controlador;
import GUI.InicioAplicacion;
import Utils.Ficheros.FicheroDatos;
import Utils.Util;
import java.util.Date;
import java.util.Vector;
import com.chaeron.GPS.GPS;
import com.chaeron.GPS.GPSListener;
import com.chaeron.GPS.event.GPSEvent;
import com.chaeron.GPS.event.GPSPosition;
import com.chaeron.GPS.exception.GPSException;

/**
 *
 * GPSJava
 * <BR><BR>
 * Implementa un GPSListener para conectar y recibir datos del dispositivo GPS
 *
 * @author  Administrador
 */
public class GeomantesDatos implements GPSListener {

    private GPS gps;
    private int primeraLocalizacion;
    private Controlador controlador;
    //private ProviderStatusListener statusListener = null;
    private static FicheroDatos coordenadaActual;
    private FicheroDatos coordenadaAntigua;
    //Distancia entre las dos ultimas coordenadas
    private double distancia;
    //Variable booleana que nos servirá para parar el thread que manda datos desde el gps
    private boolean parargps;
    private double latitud;

    /**
     * Constructor de la clase GPSJava
     *
     */
    public GeomantesDatos() {
        parargps = false;
        controlador = InicioAplicacion.getControlador();
        coordenadaActual = new FicheroDatos();
        coordenadaAntigua = new FicheroDatos();
        primeraLocalizacion = 1;
    }

    /**
     * onGPSEvent(). Callback utilizado para estar a la espera de los eventos producidos por el GPS
     * @param event
     * GPSEvent recibido por el GPS
     * @return boolean
     *
     */
    public boolean onGPSEvent(GPSEvent event) {
        boolean handled = false;
        Object eventValue = event.getValue();
        if (event.getType() == GPSEvent.GPS_EVENT_POSITION) {
            GPSPosition position = (GPSPosition) eventValue;
            latitud = position.getLatitude();
            //Si es la primera vez que recibimos una posición válida
            switch (primeraLocalizacion) {
                case 0: {
                    if (eventValue != null) {
                        controlador.setLocation(position);
                        coordenadaActual = new FicheroDatos(
                                position.getLatitude(),
                                position.getLongitude(), position.getAltitude());
                        Date d = new Date();
                        coordenadaActual.setFecha(d.toString().substring(8, 10) + "/" +
                                procesarMes(d.toString().substring(4, 7)) + "/" + d.toString().substring(d.toString().length() - 4));
                        coordenadaActual.setHora(d.toString().substring(11, 19));

                        //Calculamos la distancia recorrida entre nuestra posición actual y la anterior
                        distancia = Utils.Util.distCosineLaw(coordenadaActual, coordenadaAntigua);

                        //Calculamos el desplazamiento en píxeles
                        int[] datosEntrada;
                        datosEntrada = CalculosDatos.calcular(coordenadaActual);

                        //Calculamos la velocidad
                        int dif = Util.diferenciaMilisegundos(coordenadaActual.getHora(),
                                coordenadaAntigua.getHora());
                        double speed = Utils.Util.velocidad(distancia, dif / 1000);

                        //controlador.setEstadoProvider("Disponible");

                        //Refrescamos la pantalla con los nuevos datos
                        controlador.repaintGeomantes(coordenadaActual, datosEntrada, speed, distancia);

                        //Guardamos la coordenada actual en la antigua
                        coordenadaAntigua.clone(coordenadaActual);

                        //Si estamos en el modo grabación de ruta, añadimos la posición actual a la misma
                        /*if (controlador.getModoGrabacion()) {
                            if (rutaLatLong == null) {
                                rutaLatLong = new Vector();
                            }
                            if (rutaLatLong.size() == 0) {
                                rutaLatLong.addElement(coordenadaActual);
                            } else {
                                double distanciaGrabada = Utils.Util.distCosineLaw(coordenadaActual, ((FicheroDatos) rutaLatLong.lastElement()));

                                //Solo grabaremos el nuevo punto si está a más de 20 metros del anterior
                                if (distanciaGrabada > 0.02) {
                                    rutaLatLong.addElement(coordenadaActual);
                                }
                            }
                        }*/
                    }
                    break;
                }
                case 1: {
                    if (position != null) {
                        primeraLocalizacion = 0;
                        coordenadaAntigua = new FicheroDatos(
                                position.getLatitude(),
                                position.getLongitude(), position.getAltitude());
                        Date d = new Date();
                        coordenadaAntigua.setFecha(d.toString().substring(8, 10) + "/" +
                                procesarMes(d.toString().substring(4, 7)) + "/" + d.toString().substring(d.toString().length() - 4));
                        coordenadaAntigua.setHora(d.toString().substring(11, 19));
                        //Si estamos en el modo grabación de ruta inicializamos el vector que la almacena
                        /*if (controlador.getModoGrabacion()) {
                            rutaLatLong = new Vector();
                            rutaLatLong.addElement(coordenadaAntigua);
                        }*/

                        //Si estamos en en el modo Google Maps, le enviamos la información a CalculosDatos
                        if (controlador.getModoMapas() && controlador.getNombreMapa().compareTo("") == 0) {
                            CalculosDatos.setInfoGoogle(coordenadaAntigua, controlador.getAltoPantalla(),
                                    controlador.getAltoPantalla(), "WGS 84");
                            /*if (controlador.getNombreRuta().compareTo("") != 0) {
                            controlador.procesarRutaEnMapa();
                            }*/
                        }

                    }
                    break;
                }
                default: {
                    break;
                }
            }
        }
        return (handled);
    }

    /**
     * initGPS(). Método necesario para empezar a recibir información del dispositivo GPS
     * @return GPS
     * devuelve un objeto de la clase GPS
     *
     */
    public GPS initGPS() {
        int events = 0;

        try {
            gps = GPS.newInstance(GPS.PROTOCOL_NMEA);
            gps.setSerialPort(controlador.getPuertoSerie());	// Set real serial port parameters
            gps.setSerialCheckRead(false);
            gps.setSerialBaudRate(9600);

            //System.out.println("Connecting");

            // Allow packets with unfilled values.  These are produced until
            // the GPS gets a satellite lock.  Useful for indoor testing where
            // you can't get a lock
            gps.setBlockUnfilledPackets(false);

            // Select the events we want to receive

         /*   events |=
                    GPSEvent.GPS_EVENT_ERROR;
            events |=
                    GPSEvent.GPS_EVENT_UNKNOWN_DATA;
            events |=
                    GPSEvent.GPS_EVENT_INITIALIZED;
            events |=
                    GPSEvent.GPS_EVENT_CAPABILITIES;*/
            events |=
                    GPSEvent.GPS_EVENT_POSITION;
         /*   events |=
                    GPSEvent.GPS_EVENT_VELOCITY;
            events |=
                    GPSEvent.GPS_EVENT_HEADING;
            events |=
                    GPSEvent.GPS_EVENT_NMEA_SENTENCE;*/

            gps.addGPSListener(this, events);

            gps.connect();

            //System.out.println("Connected");

        } catch (GPSException exception) {
            //System.out.println("Error: " + exception.getMessage());
            if (gps != null) {
                try {
                    gps.disconnect();
                } catch (GPSException e) {
                    e.printStackTrace();
                }
                gps = null;
            }

        }

        return gps;
    }

    /**
     * pollGPS(). Método para preguntar al dispositivo GPS por los datos obtenidos
     *
     */
    public void pollGPS() {
        try {
            gps.poll();
        } catch (GPSException exception) {
            exception.printStackTrace();
        }

    }

    /**
     * disconnectGPS(). Método para desconectar el dispositivo GPS de forma correcta
     *
     */
    public void disconnectGPS() {
        if (gps != null) {
            try {
                gps.disconnect();
            } catch (GPSException exception) {
                System.out.println("Falló la desconexión del GPS");
            }
        }
    }

    public FicheroDatos getCoordenada() {
        return coordenadaAntigua;
    }
/*
    public static Vector getRutaGrabada() {
        return rutaLatLong;
    }*/

    public String procesarMes(
            String s) {
        String result = "";
        if (s.compareTo("Jan") == 0) {
            result = "01";
        } else if (s.compareTo("Feb") == 0) {
            result = "02";
        } else if (s.compareTo("Mar") == 0) {
            result = "03";
        } else if (s.compareTo("Apr") == 0) {
            result = "04";
        } else if (s.compareTo("May") == 0) {
            result = "05";
        } else if (s.compareTo("Jun") == 0) {
            result = "06";
        } else if (s.compareTo("Jul") == 0) {
            result = "07";
        } else if (s.compareTo("Aug") == 0) {
            result = "08";
        } else if (s.compareTo("Sep") == 0) {
            result = "09";
        } else if (s.compareTo("Oct") == 0) {
            result = "10";
        } else if (s.compareTo("Nov") == 0) {
            result = "11";
        } else if (s.compareTo("Dec") == 0) {
            result = "12";
        }

        return result;
    }

    public void pararGPS(boolean b) {
        parargps = b;
    }
}
